pub trait ThrowError<T, E>: Sized {
    fn throw_err<U>(self, msg: U) -> T
    where
        U: std::fmt::Display,
    {
        self.throw_then(|_| crate::errorln!("{}", msg))
    }

    fn throw_then<U>(self, cb: impl Fn(E) -> U) -> T;

    fn debug_error(self, debug: bool) -> Self;
}

impl<T, E> ThrowError<T, E> for Result<T, E>
where
    E: std::fmt::Debug,
{
    fn throw_then<U>(self, cb: impl Fn(E) -> U) -> T {
        match self {
            Ok(t) => t,
            Err(e) => {
                cb(e);
                std::process::exit(-1);
            }
        }
    }

    fn debug_error(self, debug: bool) -> Self {
        if debug {
            match self {
                Err(ref e) => {
                    println!("{} {:?}", console::style("DEBUG").red().bold(), e);
                    std::process::exit(-1);
                }
                _ => {}
            }
        }
        self
    }
}

/// print error msg
#[macro_export]
macro_rules! errorln {
    ($($arg:tt)*) => {{
        print!("{} ", console::style("ERR").red().bold());
        println!($($arg)*);
    }};
}

/// print error msg
#[macro_export]
macro_rules! waitln {
    ($command:expr) => {{
        println!(
            "{} Please wait ...\n",
            console::style($command).cyan().bold()
        );
    }};

    ($command:expr, $info:expr) => {{
        println!(
            "{} for {} ...\n",
            console::style($command).cyan().bold(),
            $info
        );
    }};
}
